package com.xjy.spring.thrift.core;

import com.xjy.spring.thrift.config.ThriftServerConfig;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.apache.thrift.TProcessor;
import org.apache.thrift.transport.TTransportException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import java.util.LinkedList;
import java.util.List;

public abstract class AbstractThriftServer implements InitializingBean {

    // thrift生成的service中Processor内部类的名称
    private static final String processorInnerClassName = "Processor";
    // TODO add by xujeyang 为什么使用LinkedList
    private List<ThriftServerConfig> configs = new LinkedList<ThriftServerConfig>();

    public List<ThriftServerConfig> getConfigs() {
        return configs;
    }

    public void setConfigs(List<ThriftServerConfig> configs) {
        this.configs = configs;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.notEmpty(configs, "configs can not empty");
        for (ThriftServerConfig config : configs) {
            TProcessor tProcessor = initTProcessor(config);
            asyncStartServer(tProcessor, config);
        }
    }

    /**
     * @param config
     * @return
     * @throws Exception
     */
    protected TProcessor initTProcessor(ThriftServerConfig config) throws Exception {
        System.err.println("start initTProcessor, config is " + config);
        Class<?> processorClass = ClassUtils.getClass(config.getThriftServicePackageName() + "$" + processorInnerClassName);
        TProcessor tProcessor = (TProcessor) ConstructorUtils.invokeConstructor(processorClass, config.getService());
        System.err.println("end initTProcessor, config is " + config);
        return tProcessor;
    }

    /**
     * 异步启动thrift服务
     *
     * @param tProcessor
     * @param config
     */
    protected void asyncStartServer(TProcessor tProcessor, ThriftServerConfig config) {
        // 一个tProcessor对应一个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    startServer(tProcessor, config);
                } catch (TTransportException e) {
                    throw new RuntimeException("startServer error, config is " + config, e);
                }
            }
        }).start();
    }

    /**
     * @param tProcessor
     * @param config
     */
    protected void startServer(TProcessor tProcessor, ThriftServerConfig config) throws TTransportException {
        registerThriftServer(config);
        // startThriftServer会阻塞，所以才方法registerThriftServer后面
        // 但是按常理来说，应该是先启动服务，再去注册
        startThriftServer(tProcessor, config);
    }

    protected abstract void startThriftServer(TProcessor tProcessor, ThriftServerConfig config) throws TTransportException;

    protected abstract void registerThriftServer(ThriftServerConfig config);

}
